package com.example.designpattern.creational.factory.abstract_factory;

import com.example.designpattern.creational.factory.common.product.fruit.Fruit;
import com.example.designpattern.creational.factory.common.product.mask.Mask;

/**
 * 工厂方法模式可以进一步优化，提取出公共的工厂接口
 * 这就是抽象工厂模式
 * <p>
 * 简而言之就是为一系列同类型的工厂制定了一个统一的工厂类规范，后续需求变更时便于替换工厂实现类
 */

//笔记：
//IFactory 中只有一个抽象方法时，或许还看不出抽象工厂模式的威力。实际上抽象工厂模式主要用于替换一系列方法。
//例如将程序中的 SQL Server 数据库整个替换为 Access 数据库，使用抽象方法模式的话，只需在 IFactory 接口中定义好增删改查四个方法，
//让 SQLFactory 和 AccessFactory 实现此接口，调用时直接使用 IFactory 中的抽象方法即可，调用者无需知道使用的什么数据库，
//我们就可以非常方便的整个替换程序的数据库，并且让客户端毫不知情。
//
//抽象工厂模式很好的发挥了开闭原则、依赖倒置原则，但缺点是抽象工厂模式太重了，如果 IFactory 接口需要新增功能，则会影响到所有的具体工厂类。
//使用抽象工厂模式，替换具体工厂时只需更改一行代码，但要新增抽象方法则需要修改所有的具体工厂类。
//所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求，不适合新增功能这样的纵向扩展。
//
//体会：
//本质上是一种面向抽象编程和依赖倒转设计原则的体现，由于我们依赖的是抽象的工厂而不是具体的某一个实现类，当我们需要替换工厂实现类时，
//只需要变更指定实现类的那一行代码即可，其余代码无需变更。抽象工厂中的方法越多效果越明显。
//
//简而言之就是为一系列同类型的工厂制定了一个统一的工厂类规范，后续需求变更时便于替换工厂实现类。

public interface IFactory {

    // 按理说一个抽象工厂中生产的产品应该是同一类具有关联性的，比如说手机工厂生产手机的各种配件，汽车工厂既生产轮胎又生产汽车座椅，这就是相关联的产品
    // 而轮胎又有不同的型号，再由不同的具体工厂去生产
    // 不同的汽车型号配备的轮胎不同，对应的汽车座椅也不同，如果后续要更改生产得到的汽车型号，只需要更换具体的汽车厂即可，即可同时得到不同的轮胎和座椅

    // 买水果送口罩
    Fruit createFruit();

    Mask createMask();
}
